global listaCrear
global listaInsertar
global listaDestruir
global listaImprimir
global listaFilter
global listaMap
global es_multiplo_de_5
global es_negativo
global es_largo_mayor_10
global tomar_primeros_10
global dividir_por_dos
global multiplicar_por_pi

extern malloc
extern free

%define NULL 0
%define tamanio_lista 12	;4 del int del tipo y 8 del puntero al primer elemento
%define tamanio_nodo 16		;8 del puntero al siguiente y 8 del puntero al dato
%define offset_primero 4	;offset de lista al puntero del primer elemento
%define offset_dato 8		;offset de nodo al puntero del dato

section .data


section .text

; ============ lista * listaCrear()
listaCrear:

;###### pido memoria para el struct lista
	mov RDI, tamanio_lista		; le paso el sizeof al malloc
	sub RSP, 8			; alineo la pila
	call malloc			; llamo a malloc
	add RSP, 8			; vuelvo la pila a su estado
;###### seteo en null el puntero al primero y en 0 el tipo de dato
	mov RDI, 0		
	mov [RAX], EDI			; pongo en 0 el tipo de dato
	lea RAX, [RAX + offset_primero]	; me muevo al puntero al primero
	mov RDI, NULL			
	mov [RAX], RDI			; pongo en null el puntero al primero
	lea RAX, [RAX - offset_primero]	; vuelvo a apuntar rax al comienzo del struct lista
	ret







; ============ void listaInsertar(lista * l, enum tipo e, void* dato);
;				      RDI/R8          RSI	 RDX
listaInsertar:

;###### guardo el puntero a la lista en R8
;###### dejo el tipo en RSI y el puntero al dato en RDX
	push R8				; impar
	push R15			; par
	mov R8, RDI			; guardo el puntero a la lista en R8

;###### pido memoria para el nuevo nodo
	mov RDI, tamanio_nodo		; paso el sizeof al malloc
	push RSI			; impar | pusheo por el malloc
	push RDX			; par | pusheo por el malloc
	push R8				; impar | pusheo por el malloc
	call malloc			; llamo al malloc
	pop R8				; vuelvo a poner en R8 lo que estaba
	pop RDX				; vuelvo a poner en RDX lo que estaba
	pop RSI				; vuelvo a poner en RSI lo que estaba
	mov R15, RAX			; guardo el puntero al nodo nuevo en R15

;######	seteo el dato
	lea RAX, [RAX + offset_dato]	; me posiciono donde esta el puntero al dato del nodo
	mov [RAX], RDX			; seteo el puntero al dato

;######	si la lista es vacia meto el primer nodo
	cmp qword [R8], 0		; me fijo si el puntero al primero es null //preguntar el tamaño del cmp
	jne .noVacia			; si no apunta a null es que no esta vacia, me voy a buscar el ultimo nodo para encadenar el nuevo
	mov [R8], RSI			; como era el primero no tenia tipo de dato asignado, le asigno
	lea R8, [R8 + offset_primero]	; me posiciono donde empieza el puntero al primer elemento
	mov [R8], R15			; seteo el puntero al primero
	jmp .fin			; termine de insertar el primer elemento, me voy

;######	si no era vacia busco el ultimo nodo y encadeno el nuevo
.noVacia:
	lea R8, [R8 + offset_primero]	; me posiciono en el puntero al primer nodo, el tipo de dato ya lo tiene asignado
	mov R9, [R8]			; uso R9 para guardar el puntero al nodo auxiliar
	
;######	comienzo el ciclo de busqueda, siempre voy preguntando si el puntero al siguiente es null
;######	si es null estoy al final, encadeno ahi el nuevo nodo, sino sigo buscando
.ciclo: cmp qword [R9], 0		; me fijo si el puntero al siguiente es null
	je .encadenar			; si es null estoy en el ultimo, encadeno el nuevo
	mov R9, [R9]			; si no es, apunto aux al siguiente del siguiente
	jmp .ciclo			; vuelvo al principio del ciclo a preguntar si el nuevo siguiente es null

.encadenar:
	mov [R9],R15 			; encadeno el nuevo nodo como el siguiente del ultimo

	
.fin:
	pop R15				; devuelvo R15 a su estado original
	pop R8				; devuelvo R8 a su estado original
	ret				; termine, me voy




; ============ void  listaDestruir(lista * l)
;					  RDI
listaDestruir:
	push R15			; impar | preservo lo que tenia R15
	mov R15, RDI			; guardo el puntero a la lista en R15
	call free			; libero la memoria donde estaba el struct lista
	lea R15, [R15 + offset_primero]	; apunto R15 al puntero al primer nodo
	
;######	recorro la lista hasta encontrar un siguiente que sea null, ese seria el ultimo
	
.ciclo:	cmp qword R15, 0		; comparo si el puntero al nodo es null
	je .fin				; si es null termine de borrar, me voy
	mov RDI, R15			; paso el puntero del nodo actual a free
	mov R15, [R15]			; me guardo el puntero al siguente
	call free			; libero memoria
	jmp .ciclo			; me voy a preguntar si todavia hay mas nodos
	


.fin:	pop R15
	ret

; ============ void  listaImprimir(lista  * l, char *archivo)
listaImprimir:
	ret

; ============ lista  listaFilter(lista l, void* (*funcion_filter)(void*) )
listaFilter:
	ret

; ============ lista  listaMap(lista l, void* (*funcion_map)(void*) )
listaMap:
	ret

; ============ boolean es_multiplo_de_5(int* dato)
es_multiplo_de_5:
	ret

; ============ boolean es_negativo(double* dato)
es_negativo:
	ret

; ============ boolean es_largo_mayor_10(char* dato)
es_largo_mayor_10:
	ret

; ============ int* dividir_por_dos(int* dato);
dividir_por_dos:
	ret

; ============ double* multiplicar_por_pi(double* dato);
multiplicar_por_pi:
	ret

; ============ char* tomar_primeros_10(char* dato)
tomar_primeros_10:
	ret



